package com.tool;

import com.dao.BiddingDao;
import com.dao.EquipmentDao;
import com.dao.Maintenance_orderDao;
import com.dao.UserDao;
import com.domain.*;
import org.activiti.bpmn.model.*;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.logging.Logger;

@Component
public class Until {
    @Autowired
    private UserDao userDao;

    @Autowired
    private EquipmentDao equipmentDao;

    @Autowired
    private BiddingDao biddingDao;

    @Autowired
    private Maintenance_orderDao maintenance_orderDao;

    @Resource
    private RuntimeService runtimeService;

    @Resource
    private TaskService taskService;

    @Resource
    private HistoryService historyService;

    @Resource
    private ManagementService managementService;

    @Resource
    private RepositoryService repositoryService;






    public static Until until;

    @PostConstruct
    public void init() {
        until = this;
    }

    public static User findById(Integer user_id){
        User user = until.userDao.findById(user_id);
        if (user != null && user.getRole_id() != null && user.getRole_id() == 3){
            user = until.userDao.findInsiderById(user.getId());
            InsiderUnit insiderUnit = until.userDao.findInsiderUnitByUser(user_id);
            if (insiderUnit!=null){
                user.setInsiderUnit_id(insiderUnit.getInsiderUnit_id());
                user.setInsiderUnit_name(insiderUnit.getInsiderUnit_name());
            }

            return user;
        }
        if (user != null && user.getRole_id() != null && (user.getRole_id() == 4||user.getRole_id() == 2)){
            if (user.getRole_id() == 4){
                user = until.userDao.findReviewerById(user_id);
            }
            if (user.getRole_id() == 2){
                InsiderUnit insiderUnit = until.userDao.findInsiderUnitByUser(user_id);
                User user1 = until.userDao.findEquipmentAdminRank(user_id);
                if (user1!=null && user1.getRank_name()!=null){
                    user.setRank_name(user1.getRank_name());
                }
                if (insiderUnit!=null){
                    user.setInsiderUnit_id(insiderUnit.getInsiderUnit_id());
                    user.setInsiderUnit_name(insiderUnit.getInsiderUnit_name());
                }
            }
            return user;
        }
        if (user != null && user.getRole_id() != null && user.getRole_id() == -1){
            user = until.userDao.findPersonById(user_id);
            Qualification qualification = until.userDao.findQualification(user_id);
            if (qualification != null){
                if (qualification.getQualification_image() != null){
                    user.setQualification_image(qualification.getQualification_image());
                }
                if (qualification.getDetail() != null){
                    user.setDetail(qualification.getDetail());
                }
                if (qualification.getBusiness_license() != null){
                    user.setBusiness_license(qualification.getBusiness_license());
                }
            }
        }
        if (user != null && user.getRole_id() != null && user.getRole_id() == -2){
            user = until.userDao.findPersonById(user_id);
        }
        if (user != null && user.getRole_id() != null && user.getRole_id() < 0 ){
            List<Integer> types = until.userDao.findMaintenanceTypeByCompany(user_id);
            for (Integer type:types){
                user.setType_id(type);
            }
            if (user.getType_id() == 1){
                user.setType_name("营房");
            }
            else if (user.getType_id() == 2){
                user.setType_name("装备");
            }
            else if (user.getType_id() == 3){
                user.setType_name("营房、装备");
            }
        }
        return user;
    }

    public static Maintenance_order setOrder(Maintenance_order maintenance_order){
        if (maintenance_order!=null){
            Equipment equipment = until.equipmentDao.findOneById(maintenance_order.getEquipment_id());
            String way_name = until.maintenance_orderDao.findWay(maintenance_order.getMaintenance_way_id());
            maintenance_order.setMaintenance_way_name(way_name);
            maintenance_order.setEquipment_name(equipment.getEquipment_name());
            maintenance_order.setEquipment_photos(equipment.getEquipment_photos());
            if (maintenance_order.getUnit_id()!=null){
                maintenance_order.setUnit_name(until.userDao.findNameById(maintenance_order.getUnit_id()));
            }

            List<Maintenance_process> maintenance_processList = until.maintenance_orderDao.findOrderProcess(maintenance_order.getId());
            if (maintenance_processList != null){
                for (Maintenance_process maintenance_process:maintenance_processList){
                    if (maintenance_process.getTask_id() == 1){
                        maintenance_order.setEquipment_admin_name(until.userDao.findNameById(maintenance_process.getTransactor_id()));
                        maintenance_order.setCreateTime(maintenance_process.getFinished_time());
                        User user = Until.findById(maintenance_process.getTransactor_id());
                        if (user.getInsiderUnit_name()!=null && !user.getInsiderUnit_name().isEmpty()){
                            maintenance_order.setInsiderUnit_name(user.getInsiderUnit_name());
                        }
                    }
                    if (maintenance_process.getTask_id() == 2){
                        maintenance_order.setApprover_name(until.userDao.findNameById(maintenance_process.getTransactor_id()));
                    }
                    if (maintenance_process.getTask_id() == 12){
                        maintenance_order.setMaintenanceTime(maintenance_process.getFinished_time());
                    }
                    if (maintenance_process.getTask_id() == 5){
                        maintenance_order.setMaintenanceFinishTime(maintenance_process.getFinished_time());
                    }
                }
            }
            else {
                maintenance_order.setCreateTime(new Date());
                maintenance_order.setMaintenanceTime(new Date());
            }

            maintenance_order.setBidding_num(0);
            List<Bidding> biddingList = until.biddingDao.findAllByOrder(maintenance_order.getId());
            if (biddingList!=null){
                int i = until.biddingDao.findAllByOrder(maintenance_order.getId()).size();
                if (i!=0){
                    maintenance_order.setBidding_num(i);
                }
            }
        }
        return maintenance_order;

    }

    public static int delOrder(Integer order_id){
        Maintenance_order maintenance_order = until.maintenance_orderDao.findOneById(order_id);
        if (maintenance_order == null){
            return -1;
        }
        else {
            List<Task> taskList = until.taskService.createTaskQuery()

                    .processInstanceBusinessKey(order_id.toString())
                    .list();
            if (taskList!=null){
                for (Task task:taskList){
                    until.runtimeService.deleteProcessInstance(task.getProcessInstanceId(),"1");
                    break;

                }
            }
            until.maintenance_orderDao.delAdditionalEvaluation(order_id);
            until.maintenance_orderDao.delEvaluation(order_id);
            until. maintenance_orderDao.delExpenseDetails(order_id);
            until.maintenance_orderDao.delBidding(order_id);
            until. maintenance_orderDao.delProcess(order_id);
            until. maintenance_orderDao.delRequest(order_id);
            until. maintenance_orderDao.delOrder(order_id);

            return 0;
        }
    }

    public static int delUser(Integer user_id){
        User user = until.userDao.findById(user_id);
        if (user!=null && user.getRole_id()!=null){
            if (user.getRole_id() == 3){
                until.userDao.delRank(user_id);
                until.userDao.delUser_Department(user_id);
                until.userDao.delUserInsiderUnit(user_id);
            }
            if (user.getRole_id() == -1){
                until.userDao.delUnit_Type(user_id);
                until.userDao.delQualification(user_id);
                until. userDao.delMaintenance_unit(user_id);
            }
            if (user.getRole_id() == -2){
                until. userDao.delUnit_Type(user_id);
                until.userDao.delMaintenance_unit(user_id);
            }
            if (user.getRole_id() == 4){
                until.userDao.delRank(user_id);
            }
            if (user.getRole_id() == 2){
                List<Equipment> equipmentList = until.equipmentDao.findByUser_id(user.getId());
                if (equipmentList != null){
                    for (Equipment equipment:equipmentList){
                        if (equipment.getEquipment_id() != 3 && equipment.getEquipment_id() != 6){
                            until.equipmentDao.delEquipment(equipment.getEquipment_id());
                        }
                    }
                }
                until.userDao.delRank(user_id);
                until.userDao.delUserInsiderUnit(user_id);
            }
            until.userDao.delUser_Role(user_id);
            until.userDao.delUser(user_id);
            return 0;
        }
        else {
            return -1;
        }
    }




    public static Task findTaskById(Integer id){
        Task task = until.taskService.createTaskQuery()
                .processInstanceBusinessKey(id.toString())
                .singleResult();
        return task;
    }

    //多任务实例根据维修单id和用户id查询任务
    public static Task findTaskByUserId(Integer order_id, Integer user_id){
        List<Task> taskList = until.taskService.createTaskQuery()
                .processInstanceBusinessKey(order_id.toString())
                .list();

        for (Task task:taskList){
            if (task.getAssignee().equals(user_id.toString())){
                return task;
            }
        }
        return null;
    }


    /**
     * 结束流程
     * @param processInstanceId
     */
    public static void stopAll(String processInstanceId){
        until.runtimeService.deleteProcessInstance(processInstanceId,"1");
    }


    public static int priStopOrder(Integer order_id,
                             Integer user_id,
                             String reason,
                             Integer flag){
        Maintenance_order maintenance_order = until.maintenance_orderDao.findOneById(order_id);
        if (maintenance_order == null){
            return -1;
        }
        else {
            Task task = findTaskById(order_id);
            if (task!=null){
                stopAll(task.getProcessInstanceId());
            }
            Maintenance_process process = new Maintenance_process();
            process.setOrder_id(order_id);
            process.setTask_id(14);
            process.setDetail("结束维修单");
            process.setReason(reason);
            process.setFinished_time(new Date(System.currentTimeMillis()));
            process.setTransactor_id(user_id);
            if (flag == 1){
                maintenance_order.setOrder_state(11);//普通结束
            }
            else {
                maintenance_order.setOrder_state(15);//过期结束
            }

            until.maintenance_orderDao.addProcess(process);
            until.maintenance_orderDao.updateOrder(maintenance_order);
            return 0;
        }
    }


    /**
     * 跳转到指定节点
     * @param task
     * @param targetNode
     * @param assignee
     * @return
     */
    public static int skipToTargetNode(Task task, String targetNode, String assignee){
        try {
            //获取当前节点
            String currActivityId = task.getTaskDefinitionKey();
            String processDefinitionId = task.getProcessDefinitionId();
            BpmnModel bpmnModel = until.repositoryService.getBpmnModel(processDefinitionId);
            FlowNode currFlow = (FlowNode) bpmnModel.getMainProcess().getFlowElement(currActivityId);

            if (null == currFlow) {
                List<SubProcess> subProcessList = bpmnModel.getMainProcess().findFlowElementsOfType(SubProcess.class, true);
                for (SubProcess subProcess : subProcessList) {
                    FlowElement flowElement = subProcess.getFlowElement(currActivityId);
                    if (flowElement != null) {
                        currFlow = (FlowNode) flowElement;
                        break;
                    }
                }
            }
            //获取目标节点
            FlowNode targetFlow = (FlowNode) bpmnModel.getFlowElement(targetNode);


            //记录原活动方向
            List<SequenceFlow> oriSequenceFlows = new ArrayList<>();
            oriSequenceFlows.addAll(currFlow.getOutgoingFlows());

            //清理活动方向
            currFlow.getOutgoingFlows().clear();

            //建立新的方向
            List<SequenceFlow> newSequenceFlows = new ArrayList<>();
            SequenceFlow newSequenceFlow = new SequenceFlow();
            String uuid = UUID.randomUUID().toString().replace("-", "");
            newSequenceFlow.setId(uuid);
            newSequenceFlow.setSourceFlowElement(currFlow);  //原节点
            newSequenceFlow.setTargetFlowElement(targetFlow);  //目标节点
            newSequenceFlows.add(newSequenceFlow);
            currFlow.setOutgoingFlows(newSequenceFlows);

            //完成节点任务
            while (true){
                Task task1 = until.taskService
                        .createTaskQuery().processInstanceId(task.getProcessInstanceId()).singleResult();

                until.taskService.complete(task1.getId());
                Task task2 = until.taskService
                        .createTaskQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
                if (!task2.getName().equals(task1.getName())){
                    break;
                }
            }


            //恢复原方向
            currFlow.setOutgoingFlows(oriSequenceFlows);
            Task nextTask = until.taskService
                    .createTaskQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
            // 设置执行人
            if(nextTask!=null) {
                until.taskService.setAssignee(nextTask.getId(), assignee);
            }
            return 0;
        } catch (Exception e) {
            e.printStackTrace();
            return -1;
        }


    }



    public static String targetLastNode(Task task, String nodeName){

        String processInstanceId = task.getProcessInstanceId();
        // 取得所有历史任务按时间降序排序
        List<HistoricTaskInstance> htiList = until.historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(processInstanceId)
                .orderByTaskCreateTime()
                .desc()
                .list();
        if (htiList.size()>0){
            for(HistoricTaskInstance hti:htiList){
                if (hti.getName().equals(nodeName)){
                    return hti.getId();
                }
            }
        }
        return "";

    }



    /**
     *
     * 退回到上一节点
     *
     * @param task 当前任务
     * @param num  回退几步
     */
    public static int backProcess(Task task, int num) {
        Logger logger = Logger.getGlobal();
        String processInstanceId = task.getProcessInstanceId();
        // 取得所有历史任务按时间降序排序
        List<HistoricTaskInstance> htiList = until.historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(processInstanceId)
                .orderByTaskCreateTime()
                .desc()
                .list();
        if (ObjectUtils.isEmpty(htiList) || htiList.size() < 2) {
            return -1;
        }
        // list里的第二条代表上一个任务
        HistoricTaskInstance lastTask = htiList.get(num);
        // list里第一条代表当前任务
        HistoricTaskInstance curTask = htiList.get(0);
        // 当前节点的executionId
        String curExecutionId = curTask.getExecutionId();
        // 上个节点的taskId
        String lastTaskId = lastTask.getId();

        // 上个节点的executionId
        String lastExecutionId = lastTask.getExecutionId();
        logger.info("lastTask的taskId："+lastTaskId);
        logger.info("curTask的taskId："+curTask.getId());
        if (null == lastTaskId) {

            return -2;
        }
        String processDefinitionId = lastTask.getProcessDefinitionId();
        BpmnModel bpmnModel = until.repositoryService.getBpmnModel(processDefinitionId);
        String lastActivityId = null;
        List<HistoricActivityInstance> haiFinishedList = until.historyService.createHistoricActivityInstanceQuery()
                .executionId(lastExecutionId).finished().list();
        logger.info("开始找上一个任务");
        for (HistoricActivityInstance hai : haiFinishedList) {

            if (hai.getActivityId()!=null){
                logger.info("activityId:"+hai.getActivityId());
            }
            if (hai.getActivityName()!=null){
                logger.info("activityName:"+hai.getActivityName());
            }
            if (hai.getTaskId()!=null){
                logger.info("taskId:"+hai.getTaskId());
            }
            logger.info("**********************");
            if (lastTaskId.equals(hai.getTaskId())) {
                // 得到ActivityId，只有HistoricActivityInstance对象里才有此方法
                lastActivityId = hai.getActivityId();
                logger.info("找到上一个任务");
                break;
            }
        }
        // 得到上个节点的信息
        FlowNode lastFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(lastActivityId);
        // 取得当前节点的信息
        Execution execution = until.runtimeService.createExecutionQuery().executionId(curExecutionId).singleResult();
        String curActivityId = execution.getActivityId();
        FlowNode curFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(curActivityId);
        //记录当前节点的原活动方向
        List<SequenceFlow> oriSequenceFlows = new ArrayList<>();
        oriSequenceFlows.addAll(curFlowNode.getOutgoingFlows());
        //清理活动方向
        curFlowNode.getOutgoingFlows().clear();
        //建立新方向
        List<SequenceFlow> newSequenceFlowList = new ArrayList<>();
        SequenceFlow newSequenceFlow = new SequenceFlow();
        if (lastFlowNode!=null){
            if (lastFlowNode.getId()!=null){
                logger.info("上个节点的id"+lastFlowNode.getId());
            }
            else {
                return -1;
            }
            if (lastFlowNode.getName()!=null){
                logger.info("上个节点的name"+lastFlowNode.getName());
            }
        }
        else {
            return -2;
        }
        newSequenceFlow.setId(lastFlowNode.getId());
        newSequenceFlow.setName(lastFlowNode.getName());
        newSequenceFlow.setSourceFlowElement(curFlowNode);
        newSequenceFlow.setTargetFlowElement(lastFlowNode);
        newSequenceFlowList.add(newSequenceFlow);
        curFlowNode.setOutgoingFlows(newSequenceFlowList);
        // 完成任务
        while (true){
            Task task1 = until.taskService
                    .createTaskQuery().processInstanceId(task.getProcessInstanceId()).singleResult();

            until.taskService.complete(task1.getId());
            Task task2 = until.taskService
                    .createTaskQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
            if (!task2.getName().equals(task1.getName())){
                break;
            }
        }
        //恢复原方向
        curFlowNode.setOutgoingFlows(oriSequenceFlows);
        Task nextTask = until.taskService
                .createTaskQuery().processInstanceId(processInstanceId).singleResult();
        // 设置执行人
        if(nextTask!=null) {
            until.taskService.setAssignee(nextTask.getId(), lastTask.getAssignee());
        }
        return 0;
    }

}
